<template>
  <!-- 图片预览遮罩层 -->
  <teleport to="body">
    <div
      v-if="visible"
      class="image-preview-overlay"
      @click="handleOverlayClick"
      @keydown="handleKeydown"
      tabindex="0"
    >
      <div class="image-preview-container">
        <!-- 关闭按钮 -->
        <button class="preview-close-btn" @click="close">
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
            <path d="M18 6L6 18M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
          </svg>
        </button>

        <!-- 图片容器 -->
        <div class="image-container" ref="imageContainer">
          <img
            :src="currentImageUrl"
            :alt="currentImageAlt"
            class="preview-image"
            :style="imageStyle"
            @load="handleImageLoad"
            @error="handleImageError"
            @wheel="handleWheel"
            @mousedown="handleMouseDown"
            @mousemove="handleMouseMove"
            @mouseup="handleMouseUp"
            @mouseleave="handleMouseUp"
          />
        </div>

        <!-- 左右切换箭头 -->
        <button
          v-if="images.length > 1"
          class="preview-arrow preview-arrow-left"
          @click="prevImage"
          :disabled="currentIndex === 0 && !infinite"
        >
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
            <path d="M15 18L9 12L15 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
          </svg>
        </button>

        <button
          v-if="images.length > 1"
          class="preview-arrow preview-arrow-right"
          @click="nextImage"
          :disabled="currentIndex === images.length - 1 && !infinite"
        >
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
            <path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
          </svg>
        </button>

        <!-- 底部工具栏 -->
        <div class="preview-toolbar">
          <!-- 缩放控制 -->
          <div class="zoom-controls">
            <button class="toolbar-btn" @click="zoomOut" :disabled="scale <= minScale">
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                <circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="2"/>
                <path d="M21 21L16.65 16.65M8 11h6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
              </svg>
            </button>
            <span class="zoom-text">{{ Math.round(scale * 100) }}%</span>
            <button class="toolbar-btn" @click="zoomIn" :disabled="scale >= maxScale">
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                <circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="2"/>
                <path d="M21 21L16.65 16.65M11 8v6M8 11h6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
              </svg>
            </button>
            <button class="toolbar-btn" @click="resetZoom">
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                <path d="M3 12h18m-9-9v18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
              </svg>
            </button>
          </div>

          <!-- 图片计数 -->
          <div v-if="images.length > 1" class="image-counter">
            {{ currentIndex + 1 }} / {{ images.length }}
          </div>

          <!-- 旋转控制 -->
          <div class="rotate-controls">
            <button class="toolbar-btn" @click="rotateLeft">
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                <path d="M3 3v5h5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>
            </button>
            <button class="toolbar-btn" @click="rotateRight">
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                <path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                <path d="M21 3v5h-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>
            </button>
          </div>
        </div>

        <!-- 缩略图列表 -->
        <div v-if="images.length > 1 && showThumbnails" class="thumbnail-list">
          <div
            v-for="(image, index) in images"
            :key="index"
            class="thumbnail-item"
            :class="{ active: index === currentIndex }"
            @click="goToImage(index)"
          >
            <img :src="getImageUrl(image)" :alt="getImageAlt(image)" class="thumbnail-image" />
          </div>
        </div>
      </div>
    </div>
  </teleport>
</template>

<script setup>
import { ref, reactive, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'

// Props定义
const props = defineProps({
  // 是否显示预览
  visible: {
    type: Boolean,
    default: false
  },
  // 图片数组，支持字符串数组或对象数组
  images: {
    type: Array,
    required: true,
    default: () => []
  },
  // 当前图片索引
  currentIndex: {
    type: Number,
    default: 0
  },
  // 是否无限循环
  infinite: {
    type: Boolean,
    default: true
  },
  // 是否显示缩略图
  showThumbnails: {
    type: Boolean,
    default: true
  },
  // 最小缩放比例
  minScale: {
    type: Number,
    default: 0.1
  },
  // 最大缩放比例
  maxScale: {
    type: Number,
    default: 5
  },
  // 缩放步长
  zoomStep: {
    type: Number,
    default: 0.2
  }
})

// Emits定义
const emit = defineEmits(['update:visible', 'update:currentIndex', 'change', 'close'])

// 响应式数据
const currentImageIndex = ref(props.currentIndex)
const scale = ref(1)
const rotation = ref(0)
const position = reactive({ x: 0, y: 0 })
const isDragging = ref(false)
const dragStart = reactive({ x: 0, y: 0 })
const imageContainer = ref(null)

// 计算属性
const currentImageUrl = computed(() => {
  const image = props.images[currentImageIndex.value]
  return getImageUrl(image)
})

const currentImageAlt = computed(() => {
  const image = props.images[currentImageIndex.value]
  return getImageAlt(image)
})

const imageStyle = computed(() => {
  return {
    transform: `translate(${position.x}px, ${position.y}px) scale(${scale.value}) rotate(${rotation.value}deg)`,
    transition: isDragging.value ? 'none' : 'transform 0.3s ease'
  }
})

// 工具函数
const getImageUrl = (image) => {
  if (typeof image === 'string') {
    return image.includes('http') ? image : `/images/${image}`
  }
  return image?.url || image?.src || ''
}

const getImageAlt = (image) => {
  if (typeof image === 'string') {
    return `图片 ${currentImageIndex.value + 1}`
  }
  return image?.alt || image?.title || `图片 ${currentImageIndex.value + 1}`
}

// 图片切换方法
const nextImage = () => {
  if (props.images.length <= 1) return

  if (props.infinite) {
    currentImageIndex.value = (currentImageIndex.value + 1) % props.images.length
  } else {
    if (currentImageIndex.value < props.images.length - 1) {
      currentImageIndex.value++
    }
  }
  resetImageState()
}

const prevImage = () => {
  if (props.images.length <= 1) return

  if (props.infinite) {
    currentImageIndex.value = currentImageIndex.value === 0 ? props.images.length - 1 : currentImageIndex.value - 1
  } else {
    if (currentImageIndex.value > 0) {
      currentImageIndex.value--
    }
  }
  resetImageState()
}

const goToImage = (index) => {
  if (index >= 0 && index < props.images.length) {
    currentImageIndex.value = index
    resetImageState()
  }
}

// 缩放方法
const zoomIn = () => {
  const newScale = Math.min(scale.value + props.zoomStep, props.maxScale)
  scale.value = newScale
}

const zoomOut = () => {
  const newScale = Math.max(scale.value - props.zoomStep, props.minScale)
  scale.value = newScale
}

const resetZoom = () => {
  scale.value = 1
  position.x = 0
  position.y = 0
}

// 旋转方法
const rotateLeft = () => {
  rotation.value -= 90
}

const rotateRight = () => {
  rotation.value += 90
}

// 重置图片状态
const resetImageState = () => {
  scale.value = 1
  rotation.value = 0
  position.x = 0
  position.y = 0
}

// 关闭预览
const close = () => {
  emit('update:visible', false)
  emit('close')
  resetImageState()
}

// 事件处理
const handleOverlayClick = (e) => {
  if (e.target === e.currentTarget) {
    close()
  }
}

const handleKeydown = (e) => {
  switch (e.key) {
    case 'Escape':
      close()
      break
    case 'ArrowLeft':
      prevImage()
      break
    case 'ArrowRight':
      nextImage()
      break
    case '+':
    case '=':
      e.preventDefault()
      zoomIn()
      break
    case '-':
      e.preventDefault()
      zoomOut()
      break
    case '0':
      e.preventDefault()
      resetZoom()
      break
  }
}

const handleWheel = (e) => {
  e.preventDefault()
  if (e.deltaY < 0) {
    zoomIn()
  } else {
    zoomOut()
  }
}

// 鼠标拖拽
const handleMouseDown = (e) => {
  if (scale.value <= 1) return

  isDragging.value = true
  dragStart.x = e.clientX - position.x
  dragStart.y = e.clientY - position.y
  e.preventDefault()
}

const handleMouseMove = (e) => {
  if (!isDragging.value) return

  position.x = e.clientX - dragStart.x
  position.y = e.clientY - dragStart.y
}

const handleMouseUp = () => {
  isDragging.value = false
}

const handleImageLoad = () => {
  console.log('图片加载成功')
}

const handleImageError = (e) => {
  console.error('图片加载失败:', e.target.src)
}

// 监听器
watch(() => props.currentIndex, (newIndex) => {
  currentImageIndex.value = newIndex
  resetImageState()
})

watch(currentImageIndex, (newIndex, oldIndex) => {
  emit('update:currentIndex', newIndex)
  emit('change', {
    currentIndex: newIndex,
    previousIndex: oldIndex,
    currentImage: props.images[newIndex]
  })
})

watch(() => props.visible, (visible) => {
  if (visible) {
    nextTick(() => {
      const overlay = document.querySelector('.image-preview-overlay')
      if (overlay) {
        overlay.focus()
      }
    })
  }
})

// 生命周期
onMounted(() => {
  // 阻止页面滚动
  if (props.visible) {
    document.body.style.overflow = 'hidden'
  }
})

onUnmounted(() => {
  // 恢复页面滚动
  document.body.style.overflow = ''
})

// 监听body overflow
watch(() => props.visible, (visible) => {
  if (visible) {
    document.body.style.overflow = 'hidden'
  } else {
    document.body.style.overflow = ''
  }
})

// 暴露方法
defineExpose({
  nextImage,
  prevImage,
  goToImage,
  zoomIn,
  zoomOut,
  resetZoom,
  rotateLeft,
  rotateRight,
  close
})
</script>

<style lang="scss" scoped>
.image-preview-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.9);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  outline: none;
}

.image-preview-container {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.preview-close-btn {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 40px;
  height: 40px;
  background: rgba(0, 0, 0, 0.5);
  border: none;
  border-radius: 50%;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
  transition: all 0.3s ease;

  &:hover {
    background: rgba(0, 0, 0, 0.7);
    transform: scale(1.1);
  }
}

.image-container {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.preview-image {
  max-width: 90%;
  max-height: 90%;
  object-fit: contain;
  cursor: grab;
  user-select: none;
  transform-origin: center;

  &:active {
    cursor: grabbing;
  }
}

.preview-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 50px;
  height: 50px;
  background: rgba(0, 0, 0, 0.5);
  border: none;
  border-radius: 50%;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
  transition: all 0.3s ease;

  &:hover {
    background: rgba(0, 0, 0, 0.7);
    transform: translateY(-50%) scale(1.1);
  }

  &:disabled {
    opacity: 0.3;
    cursor: not-allowed;

    &:hover {
      transform: translateY(-50%);
      background: rgba(0, 0, 0, 0.5);
    }
  }
}

.preview-arrow-left {
  left: 20px;
}

.preview-arrow-right {
  right: 20px;
}

.preview-toolbar {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.7);
  border-radius: 25px;
  padding: 10px 20px;
  display: flex;
  align-items: center;
  gap: 20px;
  z-index: 10;
}

.zoom-controls,
.rotate-controls {
  display: flex;
  align-items: center;
  gap: 8px;
}

.toolbar-btn {
  width: 36px;
  height: 36px;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;

  &:hover {
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.5);
  }

  &:disabled {
    opacity: 0.3;
    cursor: not-allowed;

    &:hover {
      background: transparent;
      border-color: rgba(255, 255, 255, 0.3);
    }
  }
}

.zoom-text {
  color: white;
  font-size: 14px;
  min-width: 50px;
  text-align: center;
}

.image-counter {
  color: white;
  font-size: 14px;
  padding: 0 10px;
  border-left: 1px solid rgba(255, 255, 255, 0.3);
  border-right: 1px solid rgba(255, 255, 255, 0.3);
}

.thumbnail-list {
  position: absolute;
  bottom: 80px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 8px;
  max-width: 80%;
  overflow-x: auto;
  padding: 10px;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 8px;
  z-index: 10;

  &::-webkit-scrollbar {
    height: 4px;
  }

  &::-webkit-scrollbar-track {
    background: rgba(255, 255, 255, 0.1);
    border-radius: 2px;
  }

  &::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.3);
    border-radius: 2px;

    &:hover {
      background: rgba(255, 255, 255, 0.5);
    }
  }
}

.thumbnail-item {
  flex-shrink: 0;
  width: 60px;
  height: 40px;
  border-radius: 4px;
  overflow: hidden;
  cursor: pointer;
  border: 2px solid transparent;
  transition: all 0.3s ease;

  &.active {
    border-color: #e74c3c;
  }

  &:hover {
    transform: scale(1.1);
  }
}

.thumbnail-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

// 响应式设计
@media (max-width: 768px) {
  .preview-close-btn {
    top: 10px;
    right: 10px;
    width: 36px;
    height: 36px;
  }

  .preview-arrow {
    width: 44px;
    height: 44px;
  }

  .preview-arrow-left {
    left: 10px;
  }

  .preview-arrow-right {
    right: 10px;
  }

  .preview-toolbar {
    bottom: 10px;
    padding: 8px 16px;
    gap: 15px;
  }

  .toolbar-btn {
    width: 32px;
    height: 32px;
  }

  .zoom-text {
    font-size: 12px;
    min-width: 40px;
  }

  .image-counter {
    font-size: 12px;
    padding: 0 8px;
  }

  .thumbnail-list {
    bottom: 60px;
    max-width: 90%;
  }

  .thumbnail-item {
    width: 50px;
    height: 35px;
  }
}
</style>
